﻿using System;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Timers;
using FileDistributor.Configuration;
using FileDistributor.FileTransfer;
using FileDistributor.IO;
using log4net;

namespace FileDistributor.Monitoring
{
    public class PickupLocationMonitor
    {
        private readonly ILog _logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
        private readonly Timer _timer = new Timer();
        private readonly PickupLocationElement _pickupLocation;
        private readonly FileDistributorSection _configSection = ConfigurationHelper.GetDistributorSection();

        public PickupLocationMonitor(PickupLocationElement pickupLocation)
        {
            if (pickupLocation == null)
            {
                throw new ArgumentNullException("pickupLocation");
            }

            _pickupLocation = pickupLocation;

            StartMonitoring();
        }

        private void StartMonitoring()
        {
            if(_pickupLocation.LocalPath != null && Directory.Exists(_pickupLocation.LocalPath)) 
            {
                _timer.Interval = _configSection.Monitor.PollInterval;
                _timer.Elapsed += TimerElapsedHandler;
                _timer.Enabled = true;
                _logger.Debug("Monitoring pickuplocation \"" + _pickupLocation.Name + "\" at directory " + _pickupLocation.LocalPath);
            }
            else
            {
                _logger.Error("Failed to monitor directory " + _pickupLocation.LocalPath + ", the path is not valid, verify that it exists.");
            }
        }

        public void TimerElapsedHandler(object sender, ElapsedEventArgs e)
        {
            try
            {
                var filePaths = Directory.GetFiles(_pickupLocation.LocalPath);

                foreach (var filePath in filePaths)
                {
                    ProcessFile(filePath);
                }
            }
            //Trådens exceptions hanteras inte av generella exceptionhanteringen i BootStrappern: CurrentDomainUnhandledException. 
            //TODO: Flytta ut denna till BootStrapper och/eller använd System.Threading.Timer. 
            catch (Exception ex) 
            {
                _logger.Error(ex.ToString());
            }
        }

        protected void ProcessFile(string sourcePath)
        {
            var fileInfo = new FileInfo(sourcePath);
            if (fileInfo.Exists)
            {
                var inProgressPath = new FileManager().MoveFile(sourcePath, ProgressState.InProgress);
                var ftpServerConnection = _configSection.FtpServerConnections.Cast<FtpServerConnectionElement>().FirstOrDefault(ftpServerConnectionElement => ftpServerConnectionElement.Name == _pickupLocation.FtpServerConnection);

                if (ftpServerConnection != null)
                {
                    var targetUri = new Uri(ftpServerConnection.Host + fileInfo.Name);
                    var credential = new NetworkCredential(ftpServerConnection.UserName, ftpServerConnection.Password);

                    var uploader = new FtpUpLoader();
                    uploader.Success += FtpUploadEventHandler.HandleSuccessEvent;
                    uploader.Failure += FtpUploadEventHandler.HandleFailureEvent;
                    uploader.Upload(inProgressPath, targetUri, credential);
                }
                else
                {
                    throw new ConfigurationErrorsException("No ftpServerConnection found with name " + _pickupLocation.FtpServerConnection + ", verify the configuration file.");
                }
            }
        }

    }
}
